// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.

#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H
#define MUDUO_NET_HTTP_HTTPREQUEST_H

#include <muduo/base/copyable.h>
#include <muduo/base/Timestamp.h>
#include <muduo/base/Types.h>

#include <map>
#include <assert.h>
#include <stdio.h>

namespace muduo
{
  namespace net
  {

    class HttpRequest : public muduo::copyable
    {
    public:
        enum Method
        {
            kInvalid, kGet, kPost, kHead, kPut, kDelete
        };
        enum Version
        {
            kUnknown, kHttp10, kHttp11
        };

        HttpRequest()
                : method_(kInvalid),
                  version_(kUnknown)
        {
        }

        void setVersion(Version v)
        {
            version_ = v;
        }

        Version getVersion() const
        {
            return version_;
        }

        bool setMethod(const char *start, const char *end)
        {
            assert(method_ == kInvalid);
            string m(start, end);
            if (m == "GET")
            {
                method_ = kGet;
            }
            else if (m == "POST")
            {
                method_ = kPost;
            }
            else if (m == "HEAD")
            {
                method_ = kHead;
            }
            else if (m == "PUT")
            {
                method_ = kPut;
            }
            else if (m == "DELETE")
            {
                method_ = kDelete;
            }
            else
            {
                method_ = kInvalid;
            }
            return method_ != kInvalid;
        }

        Method method() const
        {
            return method_;
        }

        const char *methodString() const
        {
            const char *result = "UNKNOWN";
            switch (method_)
            {
                case kGet:
                    result = "GET";
                    break;
                case kPost:
                    result = "POST";
                    break;
                case kHead:
                    result = "HEAD";
                    break;
                case kPut:
                    result = "PUT";
                    break;
                case kDelete:
                    result = "DELETE";
                    break;
                default:
                    break;
            }
            return result;
        }

        void setPath(const char *start, const char *end)
        {
            path_.assign(start, end);
        }

        const string &path() const
        {
            return path_;
        }

        void setQuery(const char *start, const char *end)
        {
            query_.assign(start, end);
        }

        const string &query() const
        {
            return query_;
        }

        void setReceiveTime(Timestamp t)
        {
            receiveTime_ = t;
        }

        Timestamp receiveTime() const
        {
            return receiveTime_;
        }

        void addHeader(const char *start, const char *colon, const char *end)
        {
            string field(start, colon);
            ++colon;
            while (colon < end && isspace(*colon))
            {
                ++colon;
            }
            string value(colon, end);
            while (!value.empty() && isspace(value[value.size() - 1]))
            {
                value.resize(value.size() - 1);
            }
            headers_[field] = value;
        }

        string getHeader(const string &field) const
        {
            string result;
            std::map<string, string>::const_iterator it = headers_.find(field);
            if (it != headers_.end())
            {
                result = it->second;
            }
            return result;
        }

        const std::map<string, string> &headers() const
        {
            return headers_;
        }

        void swap(HttpRequest &that)
        {
            std::swap(method_, that.method_);
            std::swap(version_, that.version_);
            path_.swap(that.path_);
            query_.swap(that.query_);
            receiveTime_.swap(that.receiveTime_);
            headers_.swap(that.headers_);
        }

        void setBody(const char *start, const char *end)
        {
            body_.assign(start, end);
        }

        string getBody() const
        {
            return body_;
        }


    private:
        Method method_;
        Version version_;
        string path_;
        string query_;
        string body_;
        Timestamp receiveTime_;
        std::map<string, string> headers_;
    };

  }
}

#endif  // MUDUO_NET_HTTP_HTTPREQUEST_H
